<?php

namespace app\api\controller;

use app\admin\model\Customer;
use app\admin\model\Order;
use app\admin\model\OrderDetail;
use app\admin\model\Products;
use function Workbunny\WebmanRabbitMQ\sync_publish;
use process\workbunny\rabbitmq\OrderBuilderDelayed;
use support\Db;
use support\Log;
use support\Request;
use support\Response;
use think\exception\HttpException;
use Webman\Exception\BusinessException;
use Yansongda\Pay\Pay;

class OrderController extends BaseClientController
{

    public $noNeedLogin = ["handleAliPayAsync", 'handleWechatPayAsync', 'payment'];

    /**
     * 获取指定订单的详细信息
     *
     * 此方法根据传入的订单 ID，从数据库中查询对应的订单信息，
     * 同时关联查询该订单的所有详情信息，最后将查询结果作为成功响应返回。
     *
     * @param Request $request 传入的 HTTP 请求对象，期望包含 'id' 参数用于指定订单 ID
     * @return mixed 包含指定订单及其详情信息的成功响应
     */
    public function detail(Request $request)
    {
        $uid = $request->uid;
        // 从请求的查询参数中获取订单 ID
        $id = $request->get('id');
        // 根据订单 ID 从数据库中查找对应的订单，并关联查询其订单详情信息
        $order = Order::with(['orderDetails'])->where(['user_id' => $uid])->find($id);
        // 返回包含订单详细信息的成功响应
        return $this->success($order);
    }

    /**
     * 获取订单列表并进行分页展示
     *
     * 该方法接收客户端请求，根据请求中的分页参数对订单数据进行分页查询，
     * 同时关联查询订单详情，最后返回包含订单列表和总记录数的分页数据。
     *
     * @param Request $request 传入的 HTTP 请求对象，可包含分页参数 pageNum 和 pageSize
     * @return mixed 包含订单列表和总记录数的成功响应
     */
    public function index(Request $request)
    {
        $uid = $request->uid;
        // 获取分页参数，若请求中未提供，则使用默认值，pageNum 默认值为 1，pageSize 默认值为 10
        $pageNum = $request->get('pageNum', 1);
        $pageSize = $request->get('pageSize', 10);

        // 计算查询数据的偏移量，用于确定从第几条记录开始查询
        $offset = ($pageNum - 1) * $pageSize;

        // 进行关联查询，使用 with 方法关联查询订单详情，同时使用 limit 方法实现手动分页
        // limit 方法的第一个参数为偏移量，第二个参数为每页显示的记录数
        $orders = Order::with(['orderDetails', 'orderRating'])
            ->where(['user_id' => $uid])
            ->limit($offset, $pageSize)
            ->select();

        // 获取订单表中的总记录数，用于前端计算总页数
        $total = Order::count();

        // 构造分页数据，将查询到的订单列表和总记录数封装到数组中
        $result = [
            'list' => $orders, // 订单列表数据
            'total' => $total, // 订单总记录数
        ];

        // 返回包含分页数据的成功响应
        return $this->success($result);
    }

    /**
     * 创建订单
     *
     * 此方法接收客户端请求，根据请求中的用户 ID 和商品列表创建订单，
     * 同时计算订单的总数量和总金额，最后返回创建成功的订单信息和订单详情列表。
     *
     * @param Request $request 传入的 HTTP 请求对象，包含用户 ID 和商品列表
     * @return mixed 包含订单详情列表和订单信息的成功响应
     */
    public function create(Request $request)
    {
        try {
            Db::beginTransaction();

            // 验证数据格式，从请求中获取用户 ID
            $uid = $request->uid;
            // 从请求的 POST 数据中获取商品列表
            $list = $request->post('list');

            // 创建一个新的订单实例，初始化总数量、总金额、用户 ID 和订单状态
            $order = new Order(['total_quantity' => 0, 'amount' => 0, 'user_id' => $uid, 'status' => 1]);
            // 生成订单号，格式为当前时间加上唯一标识符
            $order->order_no = date('YmdHis') . uniqid();
            // 将订单信息保存到数据库
            $order->save();

            // 初始化订单商品总数量
            $total = 0;
            // 初始化订单总金额
            $amount = 0;

            // 用于存储订单详情列表
            $orderDetailList = [];

            // 遍历商品列表，为每个商品创建订单详情
            foreach ($list as $product) {
                // 根据商品 ID 查询商品信息
                $productItem = Products::find($product['id']);

                if (!$productItem) {
                    throw new BusinessException('商品不存在');
                }

                // 创建一个新的订单详情实例，设置商品名称、数量和单价
                $orderDetail = new OrderDetail(['product_name' => $productItem['name'], 'quantity' => $product['num'], 'price' => $productItem['selling_price'], 'image' => $productItem['main_image']]);
                // 将订单详情关联到当前订单
                $orderDetail->order_id = $order['id'];
                // 累加当前商品的金额到订单总金额
                $amount = bcadd($amount, bcmul($productItem['selling_price'], $product['num'], 2), 2);
                // 累加当前商品的数量到订单商品总数量
                $total = $total + $product['num'];
                // 将订单详情信息保存到数据库
                $orderDetail->save();
                // 将订单详情添加到订单详情列表中
                array_push($orderDetailList, $orderDetail);
            }

            // 更新订单的总数量
            $order->total_quantity = $total;
            // 更新订单的总金额
            $order->amount = $amount;
            // 保存更新后的订单信息到数据库
            $order->save();

            // 发送一条队列消息 15分钟后如果订单未支付则取消订单
            sync_publish(OrderBuilderDelayed::instance(), $order->id, headers: [
                'x-delay' => 15 * 60 * 1000,
            ]);
            Db::commit();
            // 返回成功响应
            return $this->success($order->order_no);
        } catch (\Throwable $e) {

            var_dump($e->getMessage());

            Log::error($e);
            Db::rollBack();
            throw new BusinessException('创建订单失败');
        }
    }

    /**
     * 关闭指定订单，更新订单状态和删除时间
     *
     * 此方法根据传入的订单 ID 获取订单信息，将订单状态设置为 4，
     * 并将删除时间设置为当前时间，最后将更新后的信息保存到数据库，
     * 操作成功后返回成功响应。若订单不存在，抛出 404 异常。
     *
     * @param Request $request 传入的 HTTP 请求对象，期望包含 'id' 参数
     * @return mixed 操作成功的响应，表明订单已成功关闭
     * @throws HttpException 若订单不存在，抛出 404 异常
     */
    public function shutdown(Request $request)
    {
        $uid = $request->uid;
        // 从请求的查询参数中获取订单 ID
        $id = $request->get('id');
        // 根据订单 ID 从数据库中查找对应的订单
        $order = Order::where(['user_id' => $uid])->failException(false)->find($id);

        // 判断订单是否存在，若不存在则抛出 404 异常
        if (!$order) {
            throw new BusinessException('订单不存在', 404, );
        }

        // 将订单状态设置为 4，代表订单已关闭
        $order->status = 4;
        // 将订单的删除时间设置为当前时间，格式为 'YYYY-MM-DD HH:MM:SS'
        // $order->delete_time = date('Y-m-d H:i:s');
        // 将更新后的订单信息保存到数据库
        $order->save();
        // 返回操作成功的响应
        return $this->success();
    }

    public function delOrder(Request $request)
    {
        $uid = $request->uid;
        // 从请求的查询参数中获取订单 ID
        $id = $request->get('id');
        // 根据订单 ID 从数据库中查找对应的订单
        $order = Order::where(['user_id' => $uid])->failException(false)->find($id);

        // 判断订单是否存在，若不存在则抛出 404 异常
        if (!$order) {
            throw new BusinessException('订单不存在', 404);
        }

        if ($order['status'] != 4) {
            throw new BusinessException('订单未取消', 401);
        }

        // 将订单的删除时间设置为当前时间，格式为 'YYYY-MM-DD HH:MM:SS'
        $order->delete_time = date('Y-m-d H:i:s');
        // 将更新后的订单信息保存到数据库
        $order->save();
        // 返回操作成功的响应
        return $this->success();
    }

    public function handleAliPayAsync(Request $request)
    {
        // 1. 初始化配置
        Pay::config(config('payment'));

        // 2. 验证回调签名
        $alipay = Pay::alipay();
        try {
            $result = $alipay->verify($request->post()); // 验证签名
        } catch (\Exception $e) {
            Log::error('支付宝回调签名验证失败: ' . $e->getMessage());
            return new Response(400, [], 'fail');
        }

        // 3. 验证关键参数
        $outTradeNo = $result['out_trade_no'];
        $totalAmount = $result['total_amount'];
        $tradeStatus = $result['trade_status'];

        // 4. 检查交易状态
        if (!in_array($tradeStatus, ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
            Log::info('支付宝交易状态未完成: ' . $tradeStatus);
            return new Response(200, [], 'success');
        }

        // 5. 查询订单并验证金额
        $order = Order::where('order_no', $outTradeNo)->find();
        if (!$order || bccomp($order['amount'], $totalAmount, 2) !== 0) {
            Log::error('订单信息验证失败: ' . $outTradeNo);
            return new Response(400, [], 'fail');
        }

        // 6. 幂等性处理
        if ($order['status'] == 2) {
            return new Response(200, [], 'success');
        }

        // 7. 更新订单状态
        $order->status = 2;
        $order->pay_time = date('Y-m-d H:i:s');
        $order->save();

        // 8. 记录日志并响应
        Log::info('支付宝回调处理成功: ' . $outTradeNo);
        return new Response(200, [], 'success');
    }

    public function handleWechatPayAsync(Request $request)
    {
        Pay::config(config('payment'));
        $alipay = Pay::wechat();

        try {
            $data = $alipay->verify($request->all()); // 验证签名
            Log::info('『微信支付』通知: ' . json_encode($data));

            // 验证通信状态和业务结果
            if ($data['return_code'] !== 'SUCCESS' || $data['result_code'] !== 'SUCCESS') {
                Log::error('微信支付失败: ' . json_encode($data));
                return Pay::wechat()->success();
            }

            // 验证关键参数
            $outTradeNo = $data['out_trade_no'];
            $totalFee = $data['total_fee'] / 100; // 微信金额单位为分

            // 查询订单并验证金额
            $order = Order::where('order_no', $outTradeNo)->find();
            if (!$order || bccomp($order['amount'], $totalFee, 2) !== 0) {
                Log::error('订单信息验证失败: ' . $outTradeNo);
                return Pay::wechat()->success();
            }

            // 幂等性处理
            if ($order['status'] == 2) {
                return Pay::wechat()->success();
            }

            // 更新订单状态
            $order->status = 2;
            $order->pay_time = date('Y-m-d H:i:s');
            $order->save();

            Log::info('微信支付回调处理成功: ' . $outTradeNo);
        } catch (\Exception $e) {
            Log::error('微信支付回调验证失败: ' . $e->getMessage());
            // 微信支付要求无论如何都返回success，避免重复回调
        }

        return Pay::wechat()->success();
    }

    public function payment(Request $request)
    {

        $orderNo = $request->get('orderNo');
        // 根据orderNo获取订单
        $order = Order::with(['orderDetails'])->where('order_no', $orderNo)->find();

        if (!$order) {
            throw new BusinessException("订单不存在");
        }
        // 判断订单状态
        if ($order['status'] == 2 || $order['status'] == 3) {
            throw new BusinessException("订单已支付");
        }
        if ($order['status'] == 4) {
            throw new BusinessException("订单已取消");
        }
        // 判断用户agent
        $platform = $request->header('platform', 'h5');
        $paytype = $request->get('paytype');

        $orderData = [];
        if ($paytype == 1) {
            $orderData = [
                'out_trade_no' => $order['order_no'],
                'total_amount' => $order['amount'],
                'subject' => '飨親们商品订单' . $order['order_no'],
            ];
        } else if ($paytype == 2) {
            $orderData = [
                'out_trade_no' => $order['order_no'],
                'description' => '飨親们商品订单' . $order['order_no'],
                'amount' => [
                    'total' => $order['amount'],
                    'currency' => 'CNY',
                ],
                'payer' => [
                    'openid' => 'onkVf1FjWS5SBxxxxxxxx',
                ],
                'scene_info' => [
                    'payer_client_ip' => '1.2.4.8',
                    'h5_info' => [
                        'type' => 'Wap',
                    ],
                ],
            ];
        }

        if ($platform == 'h5' && $paytype == 1) {
            Pay::config(config('payment'));
            $html = Pay::alipay()->web($orderData)->getBody()->getContents(); // 支付宝h5支付
            return $this->success($html);
        } else if ($platform == 'app' && $paytype == 1) {
            Pay::config(config('payment'));
            $data = urldecode(Pay::alipay()->app($orderData)->getBody()->getContents()); // 支付宝app支付
            return $this->success($data);
        } else if ($platform == 'h5' && $paytype == 2) {
            Pay::config(config('payment'));
            $result = Pay::wechat()->h5($orderData); // 微信h5支付
            return $this->success($result);
        } else if ($platform == 'MP-WEIXIN' && $paytype == 2) {
            Pay::config(config('payment'));
            $result = Pay::wechat()->mini($orderData); // 微信小程序支付
            return $this->success($result);
        } else if ($platform == 'app' && $paytype == 2) {
            Pay::config(config('payment'));
            $result = Pay::wechat()->app($orderData); // 微信APP支付
            return $this->success($result);
        } else if ($platform == 'wxh5' && $paytype == 2) {
            Pay::config(config('payment'));
            $result = Pay::wechat()->mp($orderData); // 微信公众号支付
            return $this->success($result);
        } else if ($paytype == 3) {
            try {
                // 开启事务
                Db::beginTransaction();

                // 余额支付
                $uid = $order->user_id;

                // 查询用户余额
                $user = Customer::find($uid);
                if (!$user) {
                    throw new BusinessException('用户不存在', 404);
                }
                if ($user['balance'] < $order['amount']) {
                    throw new BusinessException('余额不足', 401);
                }

                // 更新用户余额
                $user->balance = $user->balance - $order['amount'];
                $user->save();

                // 更新订单状态
                $order->status = 2;
                $order->save();
                return $this->success([], '余额支付成功');
                // 提交事务
                Db::commit();
            } catch (\Throwable $th) {
                // 回滚事务
                Db::rollBack();
                throw $th;
            }
        }
    }
}
